/*
 * Copyright 2025 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

import QtQml 2.15
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import "keyutils.js" as KeyHelper
import org.ukui.quick.items 1.0 as UkuiItems
import org.ukui.quick.platform 1.0

Item {
    id: comboBox

    property string value: ""
    property var currentKeys: []
    property bool allowModifierLess: true
    property bool allowModifierOnly: true
    property alias labelText: label.text
    property int layoutMargins: 0
    property int itemIndex: -1
    property bool enableBackground: true
    property string currentText: ""
    property var modifierMap: ({
        [Qt.Key_Control_R]: Qt.Key_Control,
        [Qt.Key_Shift_R]: Qt.Key_Shift,
        [Qt.Key_AltGr]: Qt.Key_Alt
    })

    signal shortcutChanged(string value, int itemIndex)

    function normalizeShortcut(shortcut) {
        var genericModifiers = ["Control", "Shift", "Alt", "Meta"];
        var keys = shortcut.split('+');
        var excludeGenerics = new Set();
        for (var i = 0; i < keys.length; i++) {
            var keyOriginal = keys[i];
            var match = keyOriginal.match(/^(Control|Shift|Alt|Meta)_[LR]$/);
            if (match)
                excludeGenerics.add(match[1]);

        }
        var processedKeys = [];
        for (var j = 0; j < keys.length; j++) {
            var key = keys[j];
            if (genericModifiers.includes(key)) {
                if (!excludeGenerics.has(key))
                    processedKeys.push(key);

            } else {
                processedKeys.push(key);
            }
        }
        return processedKeys.join('+');
    }

    function cppToQml(cppStr) {
        const mapped = normalizeShortcut(cppStr).split('+').map((key) => {
            return KeyHelper.KeyMaps.cppToQml[key.trim()] || key.trim();
        });
        const filtered = mapped.filter((item, index) => {
            return mapped.indexOf(item) === index;
        });
        return filtered.join('+');
    }

    function qmlToCpp(qmlStr) {
        return qmlStr.split('+').map((key) => {
            return KeyHelper.KeyMaps.qmlToCpp[key.trim()] || key.trim();
        }).join('+');
    }

    function isOkWhenModifierless(event) {
        var isSpecialKey = event.key === Qt.Key_Return || event.key === Qt.Key_Space || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete;
        if (isSpecialKey) {
            if ((event.modifiers & Qt.ShiftModifier) != 0)
                return true;

            return false;
        } else if (event.text.length === 1) {
            return false;
        }
        return true;
    }

    function normalizeModifier(key) {
        const numKey = Number(key);
        return modifierMap[numKey] ?? numKey;
    }

    function isLetter(keyCode) {
        return (keyCode >= Qt.Key_A && keyCode <= Qt.Key_Z);
    }

    UkuiItems.StyleBackground {
        anchors.fill: parent
        useStyleTransparency: false
        visible: enableBackground
    }

    RowLayout {
        spacing: 0
        anchors.fill: parent
        anchors.leftMargin: layoutMargins
        anchors.rightMargin: layoutMargins

        UkuiItems.StyleText {
            id: label

            elide: Qt.ElideRight
            Layout.alignment: Qt.AlignLeft
            Layout.fillWidth: true
        }

        Button {
            id: control

            function updateDisplay() {
                var keys = currentKeys.map(function(data) {
                    return KeyHelper.getKeyName(data.key);
                });
                control.text = keys.join("+");
            }

            Layout.alignment: Qt.AlignRight
            implicitHeight: 36
            implicitWidth: 180
            contentItem:  UkuiItems.StyleText {
                text: parent.text
                font: parent.font
                horizontalAlignment: Text.AlignLeft
                verticalAlignment: Text.AlignVCenter
                elide: Text.ElideRight
                leftPadding: 8
            }
            text: {
                if (currentKeys.length === 0)
                    return cppToQml(value);
                var keys = currentKeys.map(function(data) {
                    return KeyHelper.getKeyName(data.key);
                });
                return keys.join("+");
            }
            Keys.onPressed: {
                if (!activeFocus)
                    return ;

                event.accepted = true;
                const rawKey = event.key;
                const normalizedKey = normalizeModifier(rawKey);
                var isIncluded = currentKeys.some(function(data) {
                    return data.key === normalizedKey;
                });
                if (isIncluded)
                    return ;

                var needModify = false;
                if (currentKeys.length === 1 && [Qt.Key_Shift, Qt.Key_Shift_R, Qt.Key_Shift_L].includes(currentKeys[0].key)) {
                    if (isLetter(normalizedKey)) {
                        currentKeys = [];
                    } else if (KeyHelper.mainKbDigitMofified.includes(event.text)) {
                        currentKeys = [];
                        needModify = true;
                    }
                }
                var done = true;
                if (control.text === "")
                    done = false;

                //修饰键状态提取.得到一个新的位掩码 modifiers2，它只包含 Shift、Ctrl、Alt、Meta 这几个修饰键的状态信息，其他无关的修饰键状态会被过滤掉
                var modifiers2 = event.modifiers & (Qt.ShiftModifier | Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier);
                //检查是否只有 Shift 键被按下
                if (modifiers2 !== 0 && (modifiers2 & ~Qt.ShiftModifier) == 0) {
                    if (!isOkWhenModifierless(event) && !allowModifierLess)
                        done = false;

                }
                if (modifiers2 !== 0 && (modifiers2 & ~Qt.MetaModifier) == 0)
                    needModify = true;

                if ((event.key === Qt.Key_Shift || event.key === Qt.Key_Control || event.key === Qt.Key_Meta || event.key === Qt.Key_Super_L || event.key === Qt.Key_Super_R || event.key === Qt.Key_Hyper_L || event.key === Qt.Key_Hyper_R || event.key === Qt.Key_Alt))
                    done = false;

                var data = {
                    "key": normalizedKey,
                    "code": event.nativeScanCode,
                    "text": event.text,
                    "isModifier": !done,
                    "needModify": needModify
                };
                currentKeys.push(data);
                updateDisplay();
                if (done)
                    control.focus = false;

            }
            Keys.onReleased: {
                event.accepted = true;
                if (!activeFocus)
                    return ;

                var done = false;
                if (allowModifierOnly && (event.key === Qt.Key_Shift || event.key === Qt.Key_Control || event.key === Qt.Key_Meta || event.key === Qt.Key_Super_L || event.key === Qt.Key_Super_R || event.key === Qt.Key_Hyper_L || event.key === Qt.Key_Hyper_R || event.key === Qt.Key_Alt))
                    done = true;

                const rawKey = event.key;
                const normalizedKey = normalizeModifier(rawKey);
                if (normalizedKey === "")
                    done = false;

                if (done)
                    control.focus = false;

            }
            onClicked: {
                forceActiveFocus();
                currentKeys = [];
                text = "...";
            }
            onFocusChanged: {
                if (!focus) {
                    if (currentKeys.length === 0) {
                        currentKeys = [];
                        text = defaultShortcut;
                        return ;
                    }
                    var modifierMatch = currentKeys.every(function(data) {
                        return data.isModifier === true;
                    });
                    // 按键全是修饰键
                    if (modifierMatch) {
                        if (currentKeys.length === 1) {
                            text = KeyHelper.KeyMaps.scanCode[currentKeys[currentKeys.length - 1].code] || "";
                        } else {
                            var isIncluded = currentKeys.some(function(data) {
                                return data.key === Qt.Key_Control;
                            });
                            if (isIncluded) {
                                if (currentKeys[0].key === Qt.Key_Control) {
                                    var additionalKey = KeyHelper.KeyMaps.scanCode[currentKeys[0].code] || "";
                                    text += additionalKey !== "" ? "+" + additionalKey : "";
                                } else {
                                    var targetIndex = -1;
                                    for (var i = 0; i < currentKeys.length; i++) {
                                        if (currentKeys[i].key === Qt.Key_Control) {
                                            targetIndex = i;
                                            break;
                                        }
                                    }
                                    if (targetIndex !== -1) {
                                        var targetElement = currentKeys.splice(targetIndex, 1)[0];
                                        currentKeys.unshift(targetElement);
                                        var keys = currentKeys.map(function(data) {
                                            return KeyHelper.getKeyName(data.key);
                                        });
                                        text = keys.join("+");
                                    }
                                    additionalKey = KeyHelper.KeyMaps.scanCode[currentKeys[currentKeys.length - 1].code] || "";
                                    text += additionalKey !== "" ? "+" + additionalKey : "";
                                }
                            } else {
                                if (currentKeys[currentKeys.length - 1].needModify === true) {
                                    additionalKey = KeyHelper.KeyMaps.scanCode[currentKeys[currentKeys.length - 1].code] || "";
                                    text += additionalKey !== "" ? "+" + additionalKey : "";
                                }
                            }
                        }
                    } else {
                        if (currentKeys.length === 1) {
                            var modified = currentKeys.some(function(data) {
                                return data.needModify === true;
                            });
                            if (modified) {
                                var modifiedKey = KeyHelper.KeyMaps.scanCode[currentKeys[currentKeys.length - 1].code] || "";
                                text = modifiedKey === "" ? text : modifiedKey;
                            } else {
                                modifiedKey = KeyHelper.KeyMaps.scanCodeKeyPad[currentKeys[currentKeys.length - 1].code] || "";
                                text = modifiedKey === "" ? text : modifiedKey;
                            }
                        }
                    }
                    shortcutChanged(qmlToCpp(text), itemIndex);
                }
            }
            Component.onCompleted: {
            }

            HoverHandler {
                id: hoverHandler
            }

            background: UkuiItems.Background {
                radius: 4
                anchors.fill: parent
                color: control.pressed ? Theme.button() : hoverHandler.hovered ? Theme.midLight() : Theme.button()
                border.color: control.activeFocus ? Theme.highlight() : "transparent"
                border.width: 2
            }

        }

    }

}
